#include "../HttpServer.h"
namespace yhaida
{
    void defaultHttpCallback(const HttpRequest &, HttpResponse *resp) // RESTful风格
    {
        resp->setStatusCode(HttpResponse::k404NotFound);
        resp->setStatusQuery("Not Found");
        resp->setCloseConnection(true);
    }
}

using namespace yhaida;
HttpServer::HttpServer(EventLoop *loop,
                       const InetAddress &listenAddr,
                       TcpServer::Option option)
    : _server(loop, listenAddr),
      _httpCallback(::defaultHttpCallback)
{
    _server.setConnectionCallback(std::bind(&HttpServer::onConnection, this, _1));
    _server.setMessageCallback(std::bind(&HttpServer::onMessage, this, _1, _2, _3));
}

void HttpServer::start()
{
    LOG_WARN << "HttpServer starts listening";
    _server.start();
}

void HttpServer::onConnection(const TcpConnectionPtr &conn)
{
    if (conn->connected())
    {
        conn->setContext(HttpContext());
    }
}
/**
 * @brief  从buffer获得http报文解析后生成一个HttpContext对象
 */
void HttpServer::onMessage(const TcpConnectionPtr &conn,
                           Buffer *buffer,
                           Timestamp receiveTime)
{
    HttpContext *context = boost::any_cast<HttpContext>(conn->getMutableContext());

    if (!context->parseRequest(buffer, receiveTime))
    {
        conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
        conn->shutdown();
    }

    if (context->gotAll())
    {
        onRequest(conn, context->request()); //根据生成响应报文
        context->reset();
    }
}
/**
 * @brief   _httpCallback是开放给用户的接口
 */
void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequest &req)
{
    const std::string &connection = req.getHeader("Connection");
    bool close = connection == "close" ||
                 (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive");

    HttpResponse response(close);

    _httpCallback(req, &response); //注册的回调函数

    Buffer buffer;
    response.appendToBuffer(&buffer);

    conn->send(&buffer);
    if (response.closeConnection())
    {
        conn->shutdown();
    }
}

std::string yhaida::readFile(const char *filename)
{
    std::string content;
    FILE *fp = ::fopen(filename, "rb");
    if (fp)
    {
        const int kBufSize = 1024 * 1024;
        char iobuf[kBufSize];
        ::setbuffer(fp, iobuf, sizeof(iobuf));

        char buf[kBufSize];
        size_t nread = 0;
        while ((nread = ::fread(buf, 1, sizeof(buf), fp)) > 0)
        {
            content.append(buf, nread);
        }
        ::fclose(fp);
    }
    return content;
}
